#include <accent/algorithms/zip.hpp>
#include <accent/algorithms/rotate.hpp>
#include <boost/fusion/sequence/comparison/equal_to.hpp>
#include <utility>
#include "test_base.hpp"

auto zipc(ivec& v1, ivec& v2) -> decltype(zip(all(v1), all(v2)))
{
  return zip(all(v1), all(v2));
}

using zt = boost::fusion::vector<int, int>;

TEST(Zip, empty_empty_isEmpty) {
  ivec v1 = {}, v2 = {};
  auto r = zipc(v1, v2);
  ASSERT_TRUE(r.empty());
}

TEST(Zip, empty_nonEmpty_isEmpty) {
  ivec v1 = {}, v2 = { -1 };
  auto r = zipc(v1, v2);
  ASSERT_TRUE(r.empty());
}

TEST(Zip, nonEmpty_empty_isEmpty) {
  ivec v1 = { 1 }, v2 = {};
  auto r = zipc(v1, v2);
  ASSERT_TRUE(r.empty());
}

TEST(Zip, oneElement_oneElement_notEmpty) {
  ivec v1 = { 1 }, v2 = { -1 };
  auto r = zipc(v1, v2);
  ASSERT_FALSE(r.empty());
}

TEST(Zip, oneElement_oneElement_frontIsTuple) {
  ivec v1 = { 1 }, v2 = { -1 };
  auto r = zipc(v1, v2);
  ASSERT_EQ(zt( 1, -1 ), r.front());
}

TEST(Zip, oneElement_oneElement_popFront_isEmpty) {
  ivec v1 = { 1 }, v2 = { -1 };
  auto r = zipc(v1, v2);
  r.pop_front();
  ASSERT_TRUE(r.empty());
}

TEST(Zip, twoElements_twoElements_popFront_frontIsSeconds) {
  ivec v1 = { 1, 2 }, v2 = { -1, -2 };
  auto r = zipc(v1, v2);
  r.pop_front();
  ASSERT_EQ(zt(2, -2), r.front());
}

TEST(Zip, threeElements_fromMiddlePosition_isCorrect) {
  ivec v1 = { 1, 2, 3 }, v2 = { -1, -2, -3 };
  auto r = zipc(v1, v2), s = r;
  s.pop_front();
  r = r.from(s.front_position());
  ASSERT_EQ(zt(2, -2), r.front());
  r.pop_front();
  ASSERT_EQ(zt(3, -3), r.front());
  r.pop_front();
  ASSERT_TRUE(r.empty());
}

TEST(Zip, threeElements_untilMiddlePosition_isCorrect) {
  ivec v1 = { 1, 2, 3 }, v2 = { -1, -2, -3 };
  auto r = zipc(v1, v2), s = r;
  s.pop_front();
  r = r.until(s.front_position());
  ASSERT_EQ(zt(1, -1), r.front());
  r.pop_front();
  ASSERT_TRUE(r.empty());
}

TEST(Zip, threeElements_rotateOne) {
  ivec v1 = { 1, 2, 3 }, v2 = { -1, -2, -3 };
  ivec e1 = { 2, 3, 1 }, e2 = { -2, -3, -1 };
  auto r = zipc(v1, v2), s = r;
  s.pop_front();
  rotate(r, s.front_position());
  ASSERT_EQ(e1, v1);
  ASSERT_EQ(e2, v2);
}
